/* * CatSaver * Copyright (C) 2015 HiHex Ltd. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see <http://www.gnu.org/licenses/>. * * */ package hihex.cs.updates; import android.app.AlertDialog; import android.app.DownloadManager; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.net.Uri; import android.os.AsyncTask; import android.text.format.Formatter; import android.text.method.ScrollingMovementMethod; import android.util.JsonReader; import android.view.View; import android.widget.TextView; import com.github.villadora.semver.SemVer; import com.google.common.base.Optional; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.text.DateFormat; import java.text.ParseException; import hihex.cs.BuildConfig; import hihex.cs.CsLog; import hihex.cs.R; /** * Obtains the latest version from GitHub, and compare with the current version. */ public final class UpdateChecker { private static final URL API_URL; private static final DateFormat STANDARD_DATE_FORMAT = DateFormat.getDateInstance(DateFormat.MEDIUM); static { try { API_URL = new URL("https://api.github.com/repos/kennytm/CatSaver/releases/latest"); } catch (final MalformedURLException e) { // Impossible. throw new RuntimeException(e); } } private Optional<ReleaseInfo> mCachedReleaseInfo = Optional.absent(); public void showCheckDialog(final Context context) { final Task task = new Task(context); task.execute((Void[]) null); } private final class Task extends AsyncTask<Void, Void, ReleaseInfo> { private Optional<ProgressDialog> mProgressDialog = Optional.absent(); private final Context mContext; public Task(final Context context) { mContext = context; final String message = context.getString(R.string.contacting_update_server); final ProgressDialog dialog = ProgressDialog.show(context, null, message, true, true); dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(final DialogInterface dialog) { mProgressDialog = Optional.absent(); cancel(true); } }); mProgressDialog = Optional.of(dialog); } @Override protected ReleaseInfo doInBackground(final Void... params) { HttpURLConnection connection = null; ReleaseInfo info = mCachedReleaseInfo.orNull(); try { connection = (HttpURLConnection) API_URL.openConnection(); connection.setRequestProperty("Accept", "application/vnd.github.v3+json"); if (info != null) { final String prevETag = info.eTag; connection.setRequestProperty("If-None-Match", prevETag); } connection.connect(); final int code = connection.getResponseCode(); if (code == 304) { return info; } info = new ReleaseInfo(); info.eTag = connection.getHeaderField("ETag"); final InputStream stream = connection.getInputStream(); final JsonReader reader = new JsonReader(new InputStreamReader(stream)); reader.setLenient(true); info.initialize(reader); return info; } catch (final IOException | ParseException e) { CsLog.e("Cannot fetch upgrade", e); } finally { if (connection != null) { connection.disconnect(); } } return info; } @Override protected void onPostExecute(final ReleaseInfo info) { mCachedReleaseInfo = Optional.of(info); if (mProgressDialog.isPresent()) { mProgressDialog.get().dismiss(); mProgressDialog = Optional.absent(); } if (SemVer.gt(info.version, BuildConfig.VERSION_NAME)) { // Release is Newer showDownloadDialog(mContext, info); } else { // Release is Older (i.e. we are up to date) showUpToDateDialog(mContext); } } } private void showUpToDateDialog(final Context context) { new AlertDialog.Builder(context) .setMessage(R.string.already_up_to_date) .setPositiveButton(android.R.string.ok, null) .show(); } private void showDownloadDialog(final Context context, final ReleaseInfo info) { final String title = context.getString(R.string.new_version_available_format, info.version); final View dialogView = View.inflate(context, R.layout.new_release_dialog, null); final TextView releaseDateView = (TextView) dialogView.findViewById(R.id.release_date); releaseDateView.setText(STANDARD_DATE_FORMAT.format(info.date)); final TextView releaseSizeView = (TextView) dialogView.findViewById(R.id.release_size); releaseSizeView.setText(Formatter.formatFileSize(context, info.size)); final TextView releaseInfoView = (TextView) dialogView.findViewById(R.id.release_info); releaseInfoView.setMovementMethod(new ScrollingMovementMethod()); releaseInfoView.setText(info.info); new AlertDialog.Builder(context) .setTitle(title) .setView(dialogView) .setPositiveButton(R.string.download, new DialogInterface.OnClickListener() { @Override public void onClick(final DialogInterface dialog, final int which) { doDownload(context, info.url, info.version); } }) .setNegativeButton(android.R.string.cancel, null) .show(); } private void doDownload(final Context context, final String url, final String version) { final DownloadManager downloader = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); final DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url)); request.setTitle("CatSaver " + version); final long downloadId = downloader.enqueue(request); UpdateReadyReceiver.sLastDownloadId = Optional.of(downloadId); } }